/* 
 * File:   ball.cpp
 * Author: iezahel
 * 
 * Created on December 28, 2008, 10:22 PM
 */

#include "ball.h"
#include "pong.h"
#include "game_protocol.h"
#include <assert.h>

Ball::Ball(SDL_Surface* surface, SDL_Surface* screen, int speed) {
    x = y = velocity_x = velocity_y = 0.0;    
    ball_surface = surface;
    screen_surface = screen;

    assert(ball_surface->w == ball_surface->h);
    
    radius = ball_surface->w / 2;

    default_ball_speed = speed;

    new_score = false;
}

Ball::Ball(const Ball& orig) {
}

Ball::~Ball() {
}

GAME_ERROR_CODES Ball::HandleNetworkInput(SDL_Event* event)
{
    GAME_ERROR_CODES err = GAME_ERROR_NONE;
    
    if (event->type == SDL_USEREVENT && event->user.code == GAME_COMMAND_BALL_STATE) {
        GameCommand* command = (GameCommand*)(event->user.data1);

        if (command->version != PROTOCOL_VERSION) { /* Verify the version protocol */
            err = GAME_ERROR_BAD_OPPONENT;
        }
        else {
            velocity_x = SDLNet_Read32(command->data); /* Get the velocity_x */
            velocity_y = SDLNet_Read32(command->data + 4); /* Get the velocity_y */
            int pos_x = SDLNet_Read32(command->data + 8); /* Get the x position */
            int pos_y = SDLNet_Read32(command->data + 12); /* Get the y position */           
            
            if (pos_x != -1 && pos_y != -1) {
                x = pos_x;
                y = pos_y;
            }
        }
    }

    return err;
}

bool Ball::CheckCollision(const SDL_Rect* rect) const
{    
    int leftC = x;
    int rightC = x + ball_surface->w;
    int topC = y;
    int bottomC = y + ball_surface->h;

    int leftR = rect->x;
    int rightR = rect->x + rect->w;
    int topR = rect->y;
    int bottomR = rect->y + rect->h;

    bool collide = !((leftC > rightR) || (rightC < leftR) || (bottomC < topR) || (topC > bottomR));
   
    collide = collide || distance(leftR, topR) <= SQR(radius) ||
                         distance(leftR, bottomR) <= SQR(radius) ||
                         distance(rightR, topR) <= SQR(radius) ||
                         distance(rightR, bottomR) <= SQR(radius);

    return collide;
}

void Ball::draw() {
    SDL_Rect offset;
   
    offset.x = (int)x;
    offset.y = (int)y;
    
    SDL_BlitSurface(ball_surface, NULL, screen_surface, &offset);
}

/*
 * Move the ball by delta_t ms in space.
 *
 * @params delta_t: How many ms have elapsed from the last movement.
 *
 *  @return: true/false if the ball has/hasn't hit the left or the right border.
 */
void Ball::move(int delta_t) {
    int screen_w = screen_surface->w;
    int screen_h = screen_surface->h;
    int ball_w = ball_surface->w;
    int ball_h = ball_surface->h;

    if (velocity_x == 0 && velocity_y == 0) return;

    int old_x = x;
    
    x += (velocity_x) * (delta_t / 1000.0);
    if (x < 0) {
        x = 0;
        velocity_x = velocity_y = 0;        
        new_score = true;        
    }
    else if (x + ball_w > screen_w) {
        x = screen_w - ball_w;
        velocity_x = velocity_y = 0;        
        new_score = true;        
    }

    y += (velocity_y) * (delta_t / 1000.0);
    if (y < 0) { y = 0; velocity_y = - velocity_y; }
    else if (y + ball_h > screen_h) { y = screen_h - ball_h; velocity_y = - velocity_y; }
}
